﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models;
using Prism.Mvvm;
using Prism.Commands;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows;
using Client.DAL;
using Panuon.UI.Silver;
using Client.Common;
using Prism.Regions;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using Microsoft.Win32;
using System.IO;
using NPOI.XSSF.UserModel;
using Newtonsoft.Json;

namespace Client.ViewModels
{
    public class CodeGenerateViewModel : BindableBase, IRegionMemberLifetime
    {
        #region 绑定属性

        //生成年度
        private string _genYear;

        public string GenYear
        {
            get { return _genYear; }
            set { SetProperty(ref _genYear, value, "GenYear"); }
        }

        //生成后缀
        private string _genSuffix;

        public string GenSuffix
        {
            get { return _genSuffix; }
            set { SetProperty(ref _genSuffix, value, "GenSuffix"); }
        }

        //生成数量
        private int _genCount;

        public int GenCount
        {
            get { return _genCount; }
            set { SetProperty(ref _genCount, value, "GenCount"); }
        }

        //商品列表
        private ObservableCollection<ProductModel> _proList;

        public ObservableCollection<ProductModel> ProList
        {
            get { return _proList; }
            set { SetProperty(ref _proList, value, "ProList"); }
        }

        //商品选择项目
        private object _selectedPro;

        public object SelectedPro
        {
            get { return _selectedPro; }
            set { SetProperty(ref _selectedPro, value, "SelectedPro"); }
        }

        //按钮工作状态
        private bool _btnGenWorking;

        public bool BtnGenWorking
        {
            get { return _btnGenWorking; }
            set { SetProperty(ref _btnGenWorking, value, "BtnGenWorking"); }
        }

        private bool _btnSaveWorking;

        public bool BtnSaveWorking
        {
            get { return _btnSaveWorking; }
            set { SetProperty(ref _btnSaveWorking, value, "BtnSaveWorking"); }
        }

        private bool _btnExpWorking;

        public bool BtnExpWorking
        {
            get { return _btnExpWorking; }
            set { SetProperty(ref _btnExpWorking, value, "BtnExpWorking"); }
        }

        //工作进程标志
        private bool _geningSeed;

        public bool GeningSeed
        {
            get { return _geningSeed; }
            set { SetProperty(ref _geningSeed, value, "GeningSeed"); }
        }

        private bool _geningGetCode;

        public bool GeningGetCode
        {
            get { return _geningGetCode; }
            set { SetProperty(ref _geningGetCode, value, "GeningGetCode"); }
        }

        private bool _geningCompare;

        public bool GeningCompare
        {
            get { return _geningCompare; }
            set { SetProperty(ref _geningCompare, value, "GeningCompare"); }
        }

        private bool _geningSort;

        public bool GeningSort
        {
            get { return _geningSort; }
            set { SetProperty(ref _geningSort, value, "GeningSort"); }
        }

        //当前进度
        private int _geningPercent;

        public int GeningPercent
        {
            get { return _geningPercent; }
            set { SetProperty(ref _geningPercent, value, "GeningPercent"); }
        }

        //编码结果列表
        private ObservableCollection<CodeModel> _codeList;

        public ObservableCollection<CodeModel> CodeList
        {
            get { return _codeList; }
            set { SetProperty(ref _codeList, value, "CodeList"); }
        }

        //显示运行中
        private Visibility _showRunning;

        public Visibility ShowRunning
        {
            get { return _showRunning; }
            set { SetProperty(ref _showRunning, value, "ShowRunning"); }
        }

        private bool _runCy;

        public bool RunCy
        {
            get { return _runCy; }
            set { SetProperty(ref _runCy, value, "RunCy"); }
        }

        //运行进度文本显示标志
        private Visibility _progressTextVis;

        public Visibility ProgressTextVisible
        {
            get { return _progressTextVis; }
            set { SetProperty(ref _progressTextVis, value, "ProgressTextVisible"); }
        }

        //运行文本内容
        private string _progressText;

        public string ProgressText
        {
            get { return _progressText; }
            set { SetProperty(ref _progressText, value, "ProgressText"); }
        }

        #endregion 绑定属性

        #region 类变量

        #endregion 类变量

        #region 命令

        public DelegateCommand StartGenCommand { get; private set; }
        public DelegateCommand SaveCodeCommand { get; private set; }
        public DelegateCommand ExportCommand { get; private set; }
        public DelegateCommand RefreshProCommand { get; private set; }

        #endregion 命令

        #region 构造函数

        public CodeGenerateViewModel()
        {
            //界面控件状态设置
            ShowRunning = Visibility.Visible;
            BtnGenWorking = false;
            BtnSaveWorking = false;
            BtnExpWorking = false;
            //初始化产品选择框和列表
            _proList = new ObservableCollection<ProductModel>();
            _codeList = new ObservableCollection<CodeModel>();
            //命令绑定
            StartGenCommand = new DelegateCommand(GenCode);
            SaveCodeCommand = new DelegateCommand(SaveCodeToDB);
            ExportCommand = new DelegateCommand(ExportToXls);
            RefreshProCommand = new DelegateCommand(GetProductList);
            //默认值
            double y = DateTime.UtcNow.Year / 100d;
            GenYear = ((int)((y - (int)y) * 100)).ToString().PadLeft(2, '0');
            GenCount = 2000;
            //读产品列表
            GetProductList();
        }

        #endregion 构造函数

        #region 方法实现

        #region 开始生成编码

        private StateModel getCodeListState;

        private async void GenCode()
        {
            if (SelectedPro == null)
            {
                ShowErr("必须选择一个产品", "生成编码");
                return;
            }
            if (GenCount < 1)
            {
                ShowErr("生成数量必须大于 1", "生成编码");
                return;
            }
            if (string.IsNullOrWhiteSpace(GenYear))
            {
                ShowErr("生成年度不能为空", "生成编码");
                return;
            }
            if (!(SelectedPro is ProductModel selPro))
            {
                ShowErr("选择的产品不正确！", "生成编码");
                return;
            }
            void callback(RetModel rm)
            {
                if (getCodeListState.CurStep != Steps.Send)
                    return;
                getCodeListState.RM = rm;
                if (rm.Success)
                    getCodeListState.RM.Data = rm.Data is null ? null : JsonConvert.DeserializeObject<List<CodeModel>>(rm.Data?.ToString());
                getCodeListState.CurStep = rm.Success ? Steps.Succ : Steps.Fail;
            }
            CodeList.Clear();
            //界面状态
            BtnGenWorking = true;
            ShowRunning = Visibility.Visible;
            RunCy = true;
            ProgressTextVisible = Visibility.Visible;
            string err = "";
            string txt = "初始化...";
            //selPro = ProSrv.GetProInfo(selPro.Id);
            ProgressText = txt;
            getCodeListState = new StateModel { CurStep = Steps.Send };
            CodeSrv.GetCodeList(callback, GenYear, GenSuffix);
            await getCodeListState.CheckState(10);
            if (getCodeListState.CurStep != Steps.Succ)
            {
                Comm.ShowErr(getCodeListState.ErrStr, "读取已存编码");
                ShowRunning = Visibility.Hidden;
                RunCy = false;
                return;
            }
            if (!(getCodeListState.RM.Data is List<CodeModel> dblist))
                dblist = new List<CodeModel>();
            var x = await Task.Run(() =>
            {
                try
                {
                    HashSet<int> hExist = new HashSet<int>();
                    Random rnd = new Random();
                    List<CodeModel> result = new List<CodeModel>();
                    List<int> tmpList;
                    HashSet<int> h = new HashSet<int>();
                    txt += "完成\r\n正在提取已存在的数据...";
                    ProgressText = txt;
                    //提取数据
                    for (int i = 0; i < dblist.Count; i++)
                    {
                        hExist.Add(dblist[i].CodeNum);
                    }
                    //去重
                    txt += "完成\r\n正在生成随机数种子并去重...";
                    ProgressText = txt;
                    tmpList = new List<int>(99999999 - hExist.Count);
                    for (int i = 1; i <= 99999999; i++)
                    {
                        h.Add(i);
                        if (h.Count >= 1000000 || i == 99999999)
                        {
                            h.ExceptWith(hExist);
                            tmpList.AddRange(h.ToList());
                            h.Clear();
                        }
                    }
                    //打乱顺序
                    txt += "完成\r\n正在排序...";
                    ProgressText = txt + $" 0/{GenCount}";
                    for (int i = 0; i < GenCount; i++)
                    {
                        int idx = rnd.Next(tmpList.Count - 1);
                        int val = tmpList[i];
                        tmpList[i] = tmpList[idx];
                        tmpList[idx] = val;
                        if (i >= 5000)
                        {
                            ProgressText = txt + $" {i + 1}/{GenCount}";
                        }
                    }
                    //生成结果
                    txt += "完成\r\n生成结果...";
                    ProgressText = txt;
                    var exchg = tmpList.Take(GenCount).ToList();
                    tmpList.Clear();
                    tmpList = exchg;
                    for (int i = 0; i < exchg.Count; i++)
                    {
                        var itm = new CodeModel
                        {
                            CodeFull = GenYear + exchg[i].ToString().PadLeft(8, '0') + GenSuffix,
                            CodeMain = exchg[i].ToString().PadLeft(8, '0'),
                            CodeNum = exchg[i],
                            CodePro = selPro.ProCode,
                            CodeSuffix = GenSuffix,
                            CodeYear = GenYear,
                            OperatorId = Comm.UserInfo.Id,
                            ProId = selPro.Id
                        };
                        result.Add(itm);
                        ProgressText = txt + $" {i + 1}/{exchg.Count}";
                    }
                    //释放资源
                    hExist.Clear();
                    hExist = null;
                    h = null;
                    tmpList.Clear();
                    tmpList = null;
                    dblist.Clear();
                    dblist = null;
                    exchg.Clear();
                    exchg = null;
                    txt += "完成";
                    ProgressText = txt;
                    GC.Collect();
                    return result;
                }
                catch (Exception ex)
                {
                    err = ex.Message;
                    return null;
                }
            });
            BtnGenWorking = false;
            ShowRunning = Visibility.Hidden;
            RunCy = false;
            ProgressText = "";
            ProgressTextVisible = Visibility.Hidden;
            if (null == x)
            {
                ShowErr(err, "生成编码");
                return;
            }
            CodeList.AddRange(x);
            x.Clear();
            x = null;
        }

        #endregion 开始生成编码

        #region 保存编码到数据库

        private StateModel saveCodeState;

        private async void SaveCodeToDB()
        {
            if (CodeList.Count < 1)
            {
                ShowErr("没有要保存的数据！", "保存编码");
                return;
            }
            ProgressText = "正在保存数据";
            ProgressTextVisible = Visibility.Visible;
            ShowRunning = Visibility.Visible;
            RunCy = true;
            BtnSaveWorking = true;
            void callback(RetModel rm)
            {
                if (saveCodeState.CurStep != Steps.Send) return;
                saveCodeState.RM = rm;
                saveCodeState.CurStep = rm.Success ? Steps.Succ : Steps.Fail;
            }
            saveCodeState = new StateModel { CurStep = Steps.Send };
            CodeSrv.AddCodeBatch(callback, _codeList.ToList());
            await saveCodeState.CheckState(10);
            if (saveCodeState.CurStep == Steps.Succ)
            {
                ShowErr("保存成功", "保存编码", MessageBoxIcon.Success);
            }
            else
            {
                ShowErr(saveCodeState.ErrStr, "保存编码", MessageBoxIcon.Error);
            }
            ProgressText = "";
            ProgressTextVisible = Visibility.Hidden;
            ShowRunning = Visibility.Hidden;
            RunCy = false;
            BtnSaveWorking = false;
        }

        #endregion 保存编码到数据库

        #region 导出编码

        private async void ExportToXls()
        {
            try
            {
                if (CodeList.Count < 1)
                {
                    ShowErr("没有要导出的数据", "导出编码");
                    return;
                }
                string fileName = "";
                SaveFileDialog f = new SaveFileDialog
                {
                    Filter = "Excel 97-2003|*.xls|Excel 2007|*.xlsx",
                    FileName = null
                };
                f.ShowDialog();
                if (f.FileName.IsNullOrEmpty())
                    return;
                fileName = f.FileName;
                string err = "";
                var x = await Task.Run(() =>
                 {
                     try
                     {
                         string txt = "正在导出...";
                         ProgressText = txt + $" 0/{CodeList.Count}";
                         ProgressTextVisible = Visibility.Visible;
                         RunCy = true;
                         ShowRunning = Visibility.Visible;
                         BtnExpWorking = true;
                         IWorkbook workBook = null;
                         FileInfo fi = new FileInfo(fileName);
                         if (fi.Extension.ToLower() == ".xlsx")
                             workBook = new XSSFWorkbook();
                         else if (fi.Extension.ToLower() == ".xls")
                             workBook = new HSSFWorkbook();
                         else
                             throw new Exception("文件后缀不正确！");
                         ISheet sheet = workBook.CreateSheet("编码");

                         #region 表头

                         IRow row = sheet.CreateRow(0);
                         ICell cell = row.CreateCell(0);
                         cell.SetCellValue("长编号");
                         cell = row.CreateCell(1);
                         cell.SetCellValue("产品编号");
                         cell = row.CreateCell(2);
                         cell.SetCellValue("年度");
                         cell = row.CreateCell(3);
                         cell.SetCellValue("随机码");
                         cell = row.CreateCell(4);
                         cell.SetCellValue("后缀");

                         #endregion 表头

                         for (int i = 0; i < CodeList.Count; i++)
                         {
                             int idx = i + 1;
                             row = sheet.CreateRow(idx);
                             row.CreateCell(0).SetCellValue(CodeList[i].CodeFull);
                             row.CreateCell(1).SetCellValue(CodeList[i].CodePro);
                             row.CreateCell(2).SetCellValue(CodeList[i].CodeYear);
                             row.CreateCell(3).SetCellValue(CodeList[i].CodeMain);
                             row.CreateCell(4).SetCellValue(CodeList[i].CodeSuffix);
                             ProgressText = txt + $" {i + 1}/{CodeList.Count}";
                         }
                         //保存文件
                         FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                         workBook.Write(fs);
                         fs.Dispose();
                         return true;
                     }
                     catch (Exception ex)
                     {
                         err = ex.Message;
                         return false;
                     }
                 });
                if (x)
                {
                    ShowErr("保存成功", "导出编码", MessageBoxIcon.Success);
                }
                else
                {
                    ShowErr(err, "导出编码", MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                ShowErr("导出失败\r\n错误信息:" + ex.Message, "导出编码");
            }
            ProgressText = "";
            BtnExpWorking = false;
            ProgressTextVisible = Visibility.Hidden;
            ShowRunning = Visibility.Hidden;
            RunCy = false;
            BtnExpWorking = false;
        }

        #endregion 导出编码

        #region 读产品列表

        private StateModel getProState;

        private async void GetProductList()
        {
            ProgressText = "正在读取产品列表...";
            ProgressTextVisible = Visibility.Visible;
            ShowRunning = Visibility.Visible;
            RunCy = true;
            ProList.Clear();
            void callback(RetModel rm)
            {
                if (getProState.CurStep != Steps.Send) return;
                getProState.RM = rm;
                getProState.RM.Data = rm.Success ? rm.Data is null ? new List<ProductModel>() : JsonConvert.DeserializeObject<List<ProductModel>>(rm.Data?.ToString()) : null;
                getProState.CurStep = rm.Success ? Steps.Succ : Steps.Fail;
            }
            getProState = new StateModel { CurStep = Steps.Send };
            ProSrv.GetProList(callback, null, null, 0);
            await getProState.CheckState(10);
            if (getProState.CurStep != Steps.Succ)
            {
                Comm.ShowErr(getProState.ErrStr, "编码生成");
                ProgressText = "";
                ShowRunning = Visibility.Hidden;
                RunCy = false;
                return;
            }
            if (getProState.RM.Data is List<ProductModel> l && l?.Count > 0)
            {
                ProList.AddRange(l);
                SelectedPro = ProList[0];
            }
            ProgressText = "";
            ShowRunning = Visibility.Hidden;
            RunCy = false;
        }

        #endregion 读产品列表

        #region 显示提示框

        private void ShowErr(string mess, string title, MessageBoxIcon mi = MessageBoxIcon.Error)
        {
            Comm.ShowErr(mess, title, mi);
        }

        #endregion 显示提示框

        bool IRegionMemberLifetime.KeepAlive => false;

        #endregion 方法实现
    }
}